import os
import datetime
from travel_recommend import settings
from rest_framework.views import APIView
from .utils import travel_data, public_travel_data
from common import response
from travel.serializers import TravelModelSerializer, Travel
from common.my_pagination import MyPageNumberPagination
from rest_framework.decorators import api_view
from travel.utils.UserCF import un_login_analysis
from travel.utils.ItemCF import recommend_item_data
import csv
import pandas as pd
from django.http.response import StreamingHttpResponse


class Tags(APIView):
    def get(self, request):
        try:
            data = travel_data.get_tags()
            return response.success_data(data)
        except:
            return response.server_error('查询失败')


class AllCity(APIView):
    def get(self, request):
        try:
            data = public_travel_data.getAllCityJson()
            return response.success_data(data)
        except:
            return response.server_error("查询数据失败，请联系管理员")


class MapData(APIView):
    def get(self, request):
        try:
            data = travel_data.getMapData()
            return response.success_data(data)
        except:
            return response.server_error("查询数据失败，请联系管理员")


class TopTravel(APIView):
    def get(self, request):
        try:
            data = travel_data.getTopTravel()
            return response.success_data(data)
        except:
            return response.server_error("查询数据失败，请联系管理员")


class TravelStar(APIView):
    def get(self, request):
        try:
            data = travel_data.getTravelStar()
            return response.success_data(data)
        except:
            return response.server_error("查询数据失败，请联系管理员")


class TravelListByCityId(APIView):
    def get(self, request):
        # 获取参数中的城市id
        city_id = request.GET.get('cityId', None)
        # 根据城市id获取所属城市的所有景点且排名
        data = travel_data.getTravelListByCityId(city_id)
        return response.success_data(data)


class SelectTravelPage(APIView):
    pg_class = MyPageNumberPagination

    def get(self, request, *args, **kwargs):
        travel_name = request.GET.get('travelName', None)
        pageNum = request.GET.get('pageNum', 1)
        pageSize = request.GET.get('pageSize', 10)
        if travel_name:
            all_user = Travel.objects.filter(name__contains=travel_name).order_by('id')
        else:
            all_user = public_travel_data.getAllTravelData().order_by('id')
        # 创建分页对象
        page = self.pg_class()
        # 在数据库中获取分页的数据
        page_list = page.paginate_queryset(all_user, request, view=self)
        # 对分页进行序列化
        ser = TravelModelSerializer(instance=page_list, many=True)

        data = {
            'pageNum': int(pageNum),
            'pageSize': int(pageSize),
            'total': all_user.count(),
            'list': ser.data,
        }
        return response.success_data(data)


@api_view(['get'])
def get_hot_travel_data(request):
    try:
        num = request.GET.get('num', 5)
        data = travel_data.getHotTravelData(int(num))
        return response.success_data(data)
    except:
        return response.server_error("查询数据失败，请联系管理员")


@api_view(['get'])
def get_travel_detail(request):
    travel_id = request.GET.get('travelId', None)
    user_id = request.GET.get('userId', None)
    data = travel_data.getTravelDetail(travel_id, user_id)
    return response.success_data(data)


# 用户未登录推荐景点接口
@api_view(['get'])
def un_login_recommend(request):
    try:
        # end：指在查找景点的个数
        end = int(request.GET.get('end', 100))
        # recom_len：为推荐景点个数
        recom_len = int(request.GET.get('recom_len', 10))
        data = un_login_analysis(end, recom_len)
        return response.success_data(data)
    except:
        return response.server_error("查询数据失败，请联系管理员")


# 基于商品协同过滤推荐
@api_view(['post'])
def recommend_item(request):
    try:
        # user_id: 推荐用户的id
        user_id = int(request.POST.get('userId'))
        data = recommend_item_data(user_id)
        return response.success_data(data)
    except:
        return response.server_error("查询数据失败，请联系管理员")


class RecommendItem(APIView):
    def get(self, request):
        try:
            # user_id: 推荐用户的id
            user_id = int(request.GET.get('userId', 42))
            print(user_id)
            data = recommend_item_data(user_id)
            return response.success_data(data)
        except:
            return response.server_error("查询数据失败，请联系管理员")


# 下载景点数据
class DownLoadTravel(APIView):
    def get(self, request):
        # 查询所有景点数据，生成为DataFrame对象，这样就可以取出字段值，组成csv文件的标题
        titles = ['name', 'price', 'star', 'address', 'detail_url', 'comment_total', 'detail_intro', 'short_intro',
                  'img_list', 'cover', 'sale_count', 'districts', 'score', 'city']
        # 查询所有用户数据
        all_data = TravelModelSerializer(Travel.objects.all(), many=True).data
        new_file_name = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + '-travel.csv'
        file_path = os.path.join(settings.FILES_MEDIA_ROOT, new_file_name)
        # 新建csv文件，写入标题
        with open(file_path, 'w', encoding='gbk', errors='ignore') as f:
            writer = csv.writer(f, delimiter=',')
            writer.writerow(titles)

        # 写入内容
        for row in all_data:
            travel = []
            for title in titles:
                travel.append(str(row[title]))
            with open(file_path, 'a', encoding='gbk', errors='ignore') as f:
                writer = csv.writer(f, delimiter=',')
                writer.writerow(travel)

        def file_iterator(file_name, chunk_size=512):
            with open(file_name) as f:
                while True:
                    c = f.read(chunk_size)
                    if c:
                        yield c
                    else:
                        break

        res = StreamingHttpResponse(file_iterator(file_path))
        # 以下两行是为让浏览器下载文件
        res['Content-Type'] = 'application/octet-stream'
        res['Content-Disposition'] = 'attachment;filename="{0}"'.format(new_file_name)
        return res

# 景点表的增删改查操作
class TravelOperation(APIView):
    # post：添加
    def post(self, request):
        request_data = request.data
        serializer = TravelModelSerializer(data=request_data)
        if serializer.is_valid():
            serializer.save()
            return response.success_msg('添加成功')
        else:
            print(serializer.errors)
            return response.success_msg('添加失败')

    # delete：删除
    def delete(self, request):
        try:
            travel_id = request.data['travelId']
            Travel.objects.get(id=travel_id).delete()
            return response.success_msg("删除成功")
        except:
            return response.server_error('删除失败')

    # put：修改
    def put(self, request):
        try:
            # 取出id
            travel_id = request.data['id']
            # 查询该景点数据
            db_user = Travel.objects.get(id=travel_id)
            # 构建序列化对象，第一个为查询到数据库数据，第二个为前端传入要更新的数据
            serializer = TravelModelSerializer(instance=db_user, data=request.data)
            # 数据校验
            if serializer.is_valid():
                serializer.save()
                return response.success_msg('修改成功')
            else:
                print(serializer.errors)
                return response.server_error('修改失败')
        except:
            return response.server_error('修改失败')

    # get：获取指定景点的数据
    def get(self, request):
        try:
            # 取出id
            travel_id = request.GET.get('travelId', None)
            # 数据库查询
            travel = TravelModelSerializer(Travel.objects.get(id=travel_id)).data
            # 拼接返回结果
            data = {
                'travel': travel
            }
            return response.success_data(data)
        except:
            return response.server_error('查询不到该景点数据')